package org.theqcp.wow.api.wowarmory;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.theqcp.wow.api.wowarmory.parsers.EquipmentParser;
import org.theqcp.wow.api.wowarmory.parsers.PlayerParser;
import org.theqcp.wow.api.wowarmory.parsers.TalentTabParser;
import org.theqcp.wow.model.api.ProgressListener;
import org.theqcp.wow.model.api.ProgressListenerAdapter;
import org.theqcp.wow.model.api.RemoteEquipmentAPI;
import org.theqcp.wow.model.api.RemotePlayerAPI;
import org.theqcp.wow.model.exceptions.EquipmentNotFoundException;
import org.theqcp.wow.model.exceptions.PlayerNotFoundException;
import org.theqcp.wow.model.exceptions.ServiceUnavailableException;
import org.theqcp.wow.model.items.Equipment;
import org.theqcp.wow.model.player.Player;
import org.theqcp.wow.model.player.Talent;
import org.theqcp.wow.utilities.http.HTTPRead;

/**
 * The service for contacting the wowarmory.
 * 
 * @author angryundead
 *
 */
public class WowArmory implements RemoteEquipmentAPI, RemotePlayerAPI {

	
	public Player getPlayer(String realm, String name) throws ServiceUnavailableException, PlayerNotFoundException {
		return this.getPlayer(realm, name, null);
	}
	
	public Player getPlayer(String realm, String name, final ProgressListener listener) throws ServiceUnavailableException, PlayerNotFoundException {
		
		//build URL
		String base = "http://www.wowarmory.com/character-sheet.xml?";
		base+="r=" + realm + "&n=" + name;
		
		//player
		Player p = null;
		
		try {
			//create url
			URL url = new URL(base);
			
			//update listener
			if(listener != null) {
				listener.updateProgress(0, "Connecting to: " + base);
			}
			
			//connect and get document
			Document d = this.connect(url);

			//update listener
			if(listener != null) {
				listener.updateProgress(10, "Retrieved raw player data.");
			}
			
			//+65%
			ProgressListener playerParseListener = new ProgressListenerAdapter(listener, 10.0, 75.0);
			
			//parse document
			p = ((new PlayerParser()).parse(d,playerParseListener));
			
			//fail out if player was not found
			if(p == null || p.getName() == null || p.getName().isEmpty()) {
				//fail!
				if(listener != null) {
					listener.fail();
				}
				throw new PlayerNotFoundException("The player " + realm + " : " + name + " was not found.");
			}
			
			//+22%
			ProgressListener talentParseListener = new ProgressListenerAdapter(listener, 75.0, 98.0);
			
			//get talents for player
			p.addTalents(this.getTalents(realm, name, talentParseListener));
			
			//update listener
			if(listener != null) {
				listener.updateProgress(100, "Player parsed.");
			}

			
		} catch (MalformedURLException e) {
			//fail!
			if(listener != null) {
				listener.fail();
			}
			throw new IllegalArgumentException("The url was malformed.");
		} catch (JDOMException e) {
			//fail!
			if(listener != null) {
				listener.fail();
			}
			throw new ServiceUnavailableException("The service returned an malformed XML message.");
		} catch (NullPointerException e) {
			//fail!
			if(listener != null) {
				listener.fail();
			}
			throw new ServiceUnavailableException("The service caused an unknown error: " + e.getMessage());
		}
		
		//calculate stats
		p.recalc();
		
		//update listener
		if(listener != null) {
			listener.updateProgress(100, "Player complete.");
			listener.complete();
		}
		
		//return player
		return p;
	}
	
	public List<Talent> getTalents(String realm, String name) throws ServiceUnavailableException {
		return this.getTalents(realm, name, null);
	}
	
	public List<Talent> getTalents(String realm, String name, final ProgressListener listener) throws ServiceUnavailableException {
		//build URL
		String base = "http://www.wowarmory.com/character-talents.xml?";
		base+="r=" + realm + "&n=" + name;
		
		List<Talent> talents = new ArrayList<Talent>();
		
		try {
			//create url
			URL url = new URL(base);
			
			//update listener
			if(listener != null) {
				listener.updateProgress(0, "Getting talents from: " + base);
			}			
			//connect and get document
			Document d = this.connect(url);
			
			//update listener
			if(listener != null) {
				listener.updateProgress(25, "Retrieved raw talent data");
			}
			
			//create listener adapter
			ProgressListener talentParseListener = new ProgressListenerAdapter(listener,25.0, 50.0);
			
			//parse document
			talents = ((new TalentTabParser()).parse(d, talentParseListener));
			
			//update listener
			if(listener != null) {
				listener.updateProgress(100, "Talents complete.");
			}
			
			//complete!
			if(listener != null) {
				listener.complete();
			}
			
		} catch (MalformedURLException ex) {

			//fail
			if(listener != null) {
				listener.fail();
			}
			
			throw new IllegalArgumentException("The url was malformed.");
		}		
		
		return talents;
	}
	
	public Equipment getEquipmentByID(String id, ProgressListener listener) throws EquipmentNotFoundException, ServiceUnavailableException{
		
		//build URL
		String base = "http://www.wowarmory.com/item-tooltip.xml?i=";
		base+= id;
		
		Equipment e = null;
		
		try {
			//create url
			URL url = new URL(base);
			
			//connect and get document
			Document d = this.connect(url);
			
			//parse document
			List<Equipment> eqList = ((new EquipmentParser()).parse(d));
			if(eqList != null && eqList.size() > 0) {
				e = eqList.get(0);
			}
			
		} catch (MalformedURLException ex) {
			throw new IllegalArgumentException("The url was malformed.");
		}		
		
		if(e == null || e.getItemName() == null || e.getItemName().isEmpty()) throw new EquipmentNotFoundException("The equipment " + id + " could not be found.");
		
		return e;
	}
	

	public Equipment getEquipmentByID(String id)
			throws EquipmentNotFoundException, ServiceUnavailableException,
			IllegalArgumentException {
		return this.getEquipmentByID(id, null);
	}

	@Override
	public List<Equipment> getEquipmentByName(String name,
			ProgressListener listener) throws EquipmentNotFoundException,
			ServiceUnavailableException, IllegalArgumentException {
		return null;
	}
	
	public List<Equipment> getEquipmentByName(String name)
			throws EquipmentNotFoundException, ServiceUnavailableException,
			IllegalArgumentException {
		return this.getEquipmentByName(name, null);
	}

	private Document connect(URL url) throws ServiceUnavailableException {
		
		Document doc = null;
		
		if(url == null) return doc;
		
		try {
			//get from url
			String out = HTTPRead.getHTTPFromURL(url,"Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4");
			
			//build
			SAXBuilder builder = new SAXBuilder();
			
			try {
				doc = builder.build(new StringReader(out));
			} catch (JDOMException e) {
				throw new ServiceUnavailableException("The service returned an malformed XML message.");
			}			
			
			if(true) {
				Format format = Format.getPrettyFormat();
				XMLOutputter outputter = new XMLOutputter(format);
				
				// serialze the xml
				StringWriter sw = new StringWriter();
				
				// format the document using SAX's pretty format output		
			    try {
					outputter.output(doc, sw);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}	    
			    
				//print
			    System.out.println(sw.toString());
			}
		
		} catch (MalformedURLException e) {
			throw new IllegalArgumentException("The url was malformed.");
		} catch (IOException e) {
			throw new ServiceUnavailableException("The service did not return a response or was otherwise unreachable.");
		}
		
		return doc;
	}

	public static void main(String[] args) {
		
//		//http://www.wowarmory.com/item-info.xml?i=38238
//		URL url = null;
//		try {
//			url = new URL("http://www.wowarmory.com/character-talents.xml?r=Skywall&n=Brace");
//		} catch (MalformedURLException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}		
//		
//		Document d = null;
//		try {
//			d = ((new WowArmory()).connect(url));
//		} catch (ServiceUnavailableException e1) {
//			// TODO Auto-generated catch block
//			e1.printStackTrace();
//		}
//		
//		if(d != null) {
//			// set the outputer to use SAX's pretty output format
//			Format format = Format.getPrettyFormat();
//			XMLOutputter outputter = new XMLOutputter(format);
//			
//			// serialze the xml
//			StringWriter sw = new StringWriter();
//			
//			// format the document using SAX's pretty format output		
//		    try {
//				outputter.output(d, sw);
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}	    
//		    
//			//print
//		    System.out.println(sw.toString());
//		    
//		}
		
		Player p = null;
		try {
			//create listener
			ProgressListener progList = new ProgressListener() {
				@Override
				public void updateProgress(double d) {
					//System.out.println(d);
				}

				@Override
				public void updateProgress(double d, String message) {
					//System.out.println(d + " : " + message);
				}

				@Override
				public void complete() {
					
				}

				@Override
				public void fail() {
					
				}
				
			};
			
			p = (new WowArmory()).getPlayer("Skywall", "Brace", progList);
			
			//force calculation
			p.recalc();
			
			//print
			System.out.println(p);
		} catch (ServiceUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (PlayerNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}
